/******************************************************************************
 * @file     intrrupt_test.c
 * @version  V0.10
 * $Revision: 1 $
 * $Date: 21/02/23 9:23a $
 * @brief    IEC60730 Interrupt Test
 * @note
 * SPDX-License-Identifier: Apache-2.0
 * Copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
 ******************************************************************************/

#include <stdio.h>
#include "nuc980.h"
#include "etimer.h"
#include "rtc.h"
#include "sys.h"
#include "user_config.h"

#define TIMER0                 	0
#define TIMER1                  1
#define TIMER2                  2
#define TIMER3                  3
#define TIMER4                  4
#define TIMER5                  5

#define TIMER1_STARTUP_FROM_32K             // Timer1 clock from 32K input
#define TIMER_DEVATION          20          // 20%
#define TIMER0_STARTUP_FREQ     1000        // Hz based (1 ms)
#define TIMER1_STARTUP_FREQ     100         // Hz based

#define	REG_RTC_CLKCTL  (RTC_BA+0x3C)       /*!< 32K Clock Control Register */

#define TEST_FAIL               0
#define TEST_PASS               1

volatile uint32_t u32SysTickCnt;
volatile uint32_t u32Timer0Cnt, u32Timer1Cnt;
uint32_t u32TimerRatio;
uint32_t u32TimeDevation;
//volatile uint32_t u32TimerIntFlag0;
static uint8_t volatile u8WDTINT = FALSE;
static uint8_t volatile u8TestResult = TEST_FAIL;

uint8_t u8IntTestPass = FALSE;
volatile int32_t   g_bAlarm  = FALSE;

void RTC_AlarmHandle(void)
{
    g_bAlarm = TRUE;
}

/**
  * @brief  RTC ISR to handle interrupt event
  * @param  None
  * @retval None
  */
void RTC_IRQHandler(void)
{
    if ( (RTC->INTEN & RTC_INTEN_ALMIEN_Msk) && (RTC->INTSTS & RTC_INTSTS_ALMIF_Msk) )
    {
        RTC->INTSTS = 0x1;

        RTC_AlarmHandle();
    }
}

/*-------------------------------------------*/
/*                init timer0                */
/*-------------------------------------------*/
static void InitTimer0(void)
{
    /**
     * select timer0 clock from clk_in (12 MHz)
     * timer0使用xin晶振的12M时钟输入
     */
    outpw(REG_CLK_DIVCTL8, inpw(REG_CLK_DIVCTL8) & ~0x30000);

    /* enable ETIMER0 engine clock */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | (1 << 8));

    /* set timer0 frequency (Hz) */
    ETIMER_Open(TIMER0, ETIMER_PERIODIC_MODE, TIMER0_STARTUP_FREQ);

}


/*-------------------------------------------*/
/*                init timer1                */
/*-------------------------------------------*/
static void InitTimer1(void)
{

#ifdef TIMER1_STARTUP_FROM_32K
    /* enable 32K clock input */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | BIT2);
    RTC->INIT = RTC_INIT_KEY;
    while(!((RTC->INIT) & 0x01));
    RTC_WaitAccessEnable();
    outpw(REG_RTC_CLKCTL, inpw(REG_RTC_CLKCTL) | BIT0);
    RTC_Check();

    /**
     * select timer1 clock from 32k
     * timer1使用32k作为时钟源
     */
    outpw(REG_CLK_DIVCTL8, inpw(REG_CLK_DIVCTL8) | 0xC0000);
#else
    /* select timer1 clock from PCLK */
    outpw(REG_CLK_DIVCTL8, (inpw(REG_CLK_DIVCTL8) & ~0x000C0000) | 0x00040000);
#endif
    /* enable ETIMER1 engine clock */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | (1 << 9));

    /**
     * set timer1 frequency (Hz)
     * timer1周期性运行
     */
    ETIMER_Open(TIMER1, ETIMER_PERIODIC_MODE, TIMER1_STARTUP_FREQ);
}

static void Start_RTC(void)
{
    S_RTC_TIME_DATA_T sInitTime;
    S_RTC_TIME_DATA_T sCurTime;

    // Enable IP clock
    outpw(REG_CLK_PCLKEN0, (inpw(REG_CLK_PCLKEN0) | (1 << 2)));

    /* Time Setting */
    sInitTime.u32Year       = 2017;
    sInitTime.u32Month      = 5;
    sInitTime.u32Day        = 1;
    sInitTime.u32Hour       = 12;
    sInitTime.u32Minute     = 30;
    sInitTime.u32Second     = 0;
    sInitTime.u32DayOfWeek  = RTC_MONDAY;
    sInitTime.u32TimeScale  = RTC_CLOCK_24;

    RTC_Open(&sInitTime);

    g_bAlarm = FALSE;

    /* Get the current time */
    RTC_GetDateAndTime(&sCurTime);

    /* The alarm time setting */
    sCurTime.u32Second = sCurTime.u32Second + 10;

    /* Set the alarm time */
    RTC_SetAlarmDateAndTime(&sCurTime);

    /* Clear interrupt status */
    RTC->INTSTS = RTC_INTSTS_ALMIF_Msk;

    /* Enable RTC Alarm Interrupt */
    sysInstallISR(IRQ_LEVEL_1, IRQ_RTC, (PVOID)RTC_IRQHandler);
    sysSetLocalInterrupt(ENABLE_IRQ);
    sysEnableInterrupt(IRQ_RTC);

    RTC_EnableInt(RTC_INTEN_ALMIEN_Msk);
    while(!g_bAlarm)
        ; //wait for RTC interrupt

    /* Disable RTC Alarm Interrupt */
    RTC_DisableInt(RTC_INTEN_ALMIEN_Msk);
    /**
     * check test result
     * 检测误差偏移在正负20%
     */
    if ((u32Timer0Cnt>= TIMER0_STARTUP_FREQ-TIMER_DEVATION)
            && (u32Timer0Cnt<= TIMER0_STARTUP_FREQ+TIMER_DEVATION))
        u8IntTestPass = TEST_PASS;
    else
        u8IntTestPass = TEST_FAIL;
}

uint8_t IEC60730_timer_Test(void)
{

    /* init timer0 */
    InitTimer0();
    u32Timer0Cnt = 0;

    /* init timer1 */
    InitTimer1();
    u32Timer1Cnt = 0;
    /* start timer0 and timer1 */
    ETIMER_Start(TIMER0);
    ETIMER_Start(TIMER1);
    Start_RTC();
    /* stop timer0 and timer1 */
    ETIMER_Stop(TIMER0);
    ETIMER_Stop(TIMER1);

    return u8IntTestPass;
}

/*** (C) COPYRIGHT 2013 Nuvoton Technology Corp. ***/
